/**
 * @file Contacts.cs
 * @author Zane Mayo
 * @date 6/5/2009
 */

using System;
using System.Collections.Generic;

namespace MxitAPI {
	
	/**
	 * Keeps track of all contacts
	 */
	public class Contacts {
		
		private static log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod().DeclaringType );
		
        
        public event ContactsEventHandler ContactAdded;
        public event ContactsEventHandler ContactRemoved;
        public event ContactsEventHandler ContactChanged;
        public event NewSubscriptionEventHandler NewSubscription;

		/// Singleton instance of this class
		static private Contacts instance;
		
		/// Maps the unique string address used by mxit to this applications way of storing contacts uniquely ( using integers )
		private Dictionary<string , int> contactAddressToId;
		
		/// Maps the unique key used by this application onto the list of contacts
		private Dictionary<int, Contact> contacts;

        /// Holds the information for incoming subscriptions
        private List<RawSubscription> subscriptions;
		
		/// Holds the current unique id for contacts
		private int currentContactId;
		
		
		private Contacts() {
			contactAddressToId = new Dictionary<string, int>();
			contacts = new Dictionary<int, Contact>();
			currentContactId = 0;
            subscriptions = new List<RawSubscription>();
		}
		
		static public Contacts Instance {
			get {
				if ( instance == null )
					instance = new Contacts();
				return instance;
			}
		}
		
		public int Count {
			get {
				return contacts.Count;
			}
		}
		
		/**
		 * Adds a contact to the contact list and returns the unique key to access it
		 * @param rawContact The details of the contact that must be created received from the mxit servers
		 * @return The unique id of this contact
		 */
		public int AddContact( RawContact rawContact ) {
					
			if ( rawContact.ContactAddress == null ) 
				throw new MxitException( "The ContactAddress of the RawContact to add cannot be null" );
			
			int returnContactId;
			
			// If this contact does not exist, create it
			if ( !contactAddressToId.TryGetValue( rawContact.ContactAddress, out returnContactId ) ) {
				Contact contact = new Contact( currentContactId, rawContact );
				contactAddressToId.Add( contact.ContactAddress, currentContactId );
				contacts.Add( currentContactId, contact );
				returnContactId = currentContactId;
				++currentContactId;
                ContactAdded( this, new ContactsEventArgs( contact ) );
			}
			// Update the contacts information by replacing it with a new contact
			else {
				Contact contact = new Contact( returnContactId, rawContact );
				contacts[ returnContactId ] = contact;
                ContactChanged( this, new ContactsEventArgs( contact) );
			}
			
			return returnContactId;
		}
		
		/**
		 * Create the skeleton of a contact by only using the contact address.
		 * Used when messages are sent without contact details coming through first ( as in the login )
		 * @param contactAddress The unique string id used by mxit do differentiate between contacts
		 * @return The unique id of this contact
		 */
		public int AddContact( string contactAddress ) {
			Contact contact = new Contact( currentContactId, contactAddress );
			
			if ( contact.ContactAddress == null ) 
				throw new MxitException( "The ContactAddress of the contact to add cannot be null" );
			
			int returnContactId;
			
			// If this contact does not exist, create it
			if ( !contactAddressToId.TryGetValue( contact.ContactAddress, out returnContactId ) ) {
				contactAddressToId.Add( contact.ContactAddress, currentContactId );
				contacts.Add( currentContactId, contact );
				returnContactId = currentContactId;
				++currentContactId;
                ContactAdded( this, new ContactsEventArgs( contact ) );
			}
			
			return returnContactId;
			
		}
		
		/**
		 * Gets a contact by its unique application Id
		 * @return the contact that is matched to the unique application contact Id
		 */
		public Contact GetContact( int id ) {
			Contact returnContact;
			if( contacts.TryGetValue( id, out returnContact ) )
				return returnContact;
			else 
				return null;
		}
		
		/**
		 * Gets a contact by the contactAddress string given by the Mxit servers
		 * @return the contact that is matched to the unique mxit contact address
		 */
		public Contact GetContact( string contactAddress ) {
			if ( contactAddress == null ) 
				return null;
			
			int id;
			if( contactAddressToId.TryGetValue( contactAddress, out id ) )
				return GetContact( id );
			else 
				return null;
		}

        public List<Contact> GetAllContacts() {
           // contacts.Values;
            List<Contact> list = new List<Contact>( contacts.Values );
            return list;
        }

        public void AddSubscription( RawSubscription rawSubscription ) {
            subscriptions.Add( rawSubscription );
            NewSubscription( this, new NewSubscriptionEventArgs( rawSubscription ) );
        }



        /*public void DoContactsEvent() {
            contactsEvent( this, null );
        }*/

        public void DoContactChanged( int contactId ) {
            Contact contact;
            if ( contacts.TryGetValue( contactId, out contact ) ) {
                ContactChanged( this, new ContactsEventArgs( contact ) );
            }
        }
		
		
	}
}
